/* ----------------------------------------------------------------------------
* File: api_message_sender_impl.cpp
*
* Desc: Skype message sender implementation
*
* Created: 30/07/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#include "api_message_sender_impl.h"

#define WAIT_TIME_MESSAGE_SENDER	5
#define WAIT_TIME_ATTACH			200

namespace SkypeProtection
{
	APIMessageSenderImpl::APIMessageSenderImpl()
		: APIProxy(false)
	{
		using namespace Common::Utils;
		ConcurrentQueueParams params;
		m_RequestQueue.reset(new ConcurrentQueue<SendingRequest>(params));
	}

	APIMessageSenderImpl::~APIMessageSenderImpl()
	{
		Stop();
	}

	Common::Error APIMessageSenderImpl::RunLogic(SKYPE4COMLib::ISkype* skype)
	{
		if (StartProxyProcess(skype) != Common::SKYPE_SUCCESS)
			return Common::SKYPE_ERROR;

		ProcessRequests(skype);

		StopProxyProcess(skype);
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIMessageSenderImpl::AsyncSendMessage(const std::string& ChatName, const std::string& Message)
	{
		SendingRequest request;
		request.ChatName = ChatName;
		request.Data = Message;

		m_RequestQueue->push(request);
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIMessageSenderImpl::StartProxyProcess(SKYPE4COMLib::ISkype* skype)
	{
		m_Logger->Print("SkypeMessageSender::StartProxyProcess() - start");

		// Start client
		if (skype->GetClient()->IsRunning == VARIANT_FALSE)
			skype->GetClient()->Start(VARIANT_TRUE, VARIANT_FALSE);

		// Connect to Skype API without waiting
		skype->Attach(6, VARIANT_FALSE);

		// Wait API permission
		SKYPE4COMLib::TAttachmentStatus attachStatus = skype->GetAttachmentStatus();
		while (attachStatus != SKYPE4COMLib::TAttachmentStatus::apiAttachSuccess)
		{
			if (attachStatus == SKYPE4COMLib::TAttachmentStatus::apiAttachRefused)
			{
				m_Logger->Print("SkypeMessageSender: attach refused (FAILED)");
				throw Common::Exception("Object was refused");
			}

			Sleep(WAIT_TIME_ATTACH);
			attachStatus = skype->GetAttachmentStatus();
		}

		m_Logger->Print("SkypeMessageSender: attached (OK)");
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIMessageSenderImpl::StopProxyProcess(SKYPE4COMLib::ISkype* skype)
	{
		return Common::SKYPE_SUCCESS;
	}

	void APIMessageSenderImpl::ProcessRequests(SKYPE4COMLib::ISkype* Skype)
	{
		while(!QueryExitStatus(WAIT_TIME_MESSAGE_SENDER))
		{
			size_t sizeQueue = m_RequestQueue->size();
			while(sizeQueue > 0)
			{
				m_Logger->Print("SkypeProxy: REQUEST_SENDING_MESSAGE request");

				SendingRequest request = m_RequestQueue->front();
				SendData(Skype, request);

				m_RequestQueue->pop();
				--sizeQueue;
			}
		}
	}

	SKYPE4COMLib::IChatPtr APIMessageSenderImpl::FindChatByName(SKYPE4COMLib::ISkype* Skype, const std::string& ChatName)
	{
		SKYPE4COMLib::IChatPtr Chat = NULL;
		if (Skype)
		{
			SKYPE4COMLib::IChatCollectionPtr collection = Skype->GetChats();
			for (long i = 1; i < collection->GetCount(); ++i)
			{
				if (!strcmp(ChatName.c_str(), (LPCSTR)collection->GetItem(i)->Name))
				{
					Chat = collection->GetItem(i);
					break;
				}
			}
		}
		return Chat;
	}

	Common::Error APIMessageSenderImpl::SendData(SKYPE4COMLib::ISkype* Skype, const SendingRequest& request)
	{
		// Find chat for sending
		SKYPE4COMLib::IChatPtr Chat = FindChatByName(Skype, request.ChatName);
		if (Chat == NULL)
		{
			m_Logger->Print("SkypeProxy: ERROR - Unable to find chat for sending message");
			return Common::SKYPE_ERROR;
		}

		Chat->SendMessage(request.Data.c_str());
		Chat = NULL;

		return Common::SKYPE_SUCCESS;
	}

	std::auto_ptr<APIMessageSender> CreateAPIMessageSender(const APIMessageSenderParams& params)
	{
		std::auto_ptr<APIMessageSender> sender;
		try
		{
			std::auto_ptr<APIMessageSenderImpl> obj(new APIMessageSenderImpl());

			// Start message sender
			if (obj->Start() != Common::SKYPE_SUCCESS)
				return sender;

			sender = obj;
		}
		catch(const Common::Exception&)
		{
		}
		return sender;
	}
}